home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Tool Chest / Dev.CD Feb 97 TC.toast / Sample Code / Development Tools & Languages / AppsToGo / DTS.Lib / AEWFMT.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-22  |  27.0 KB  |  1,114 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        AEWFMT.c
  5. ** Written by:    Eric Soldan
  6. **
  7. ** Copyright © 1993 Apple Computer, Inc.
  8. ** All rights reserved.
  9. */
  10.  
  11. /* You may incorporate this sample code into your applications without
  12. ** restriction, though the sample code has been provided "AS IS" and the
  13. ** responsibility for its operation is 100% yours.  However, what you are
  14. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  15. ** after having made changes. If you're going to re-distribute the source,
  16. ** we require that you make it clear in the source that the code was
  17. ** descended from Apple Sample Code, but that you've made changes. */
  18.  
  19.  
  20.  
  21. /*****************************************************************************/
  22.  
  23.  
  24.  
  25. #include "DTS.Lib2.h"
  26. #include "DTS.Lib.protos.h"
  27.  
  28. #ifndef __ERRORS__
  29. #include <Errors.h>
  30. #endif
  31.  
  32. #ifndef __RESOURCES__
  33. #include <Resources.h>
  34. #endif
  35.  
  36. #ifndef __TEXTEDITCONTROL__
  37. #include "TextEditControl.h"
  38. #endif
  39.  
  40. #ifndef __TOOLUTILS__
  41. #include <ToolUtils.h>
  42. #endif
  43.  
  44.  
  45.  
  46. /*****************************************************************************/
  47.  
  48.  
  49.  
  50. extern Boolean            gHasAppleEvents, gQuitApplication;
  51. extern TreeObjHndl        gWindowFormats;
  52.  
  53. static pascal OSErr        ReceiveWFMT(AppleEvent *message, AppleEvent *reply, long refcon);
  54. static void                MergeAppResources(StringPtr suffix);
  55. static void                DupWFMT(StringPtr suffix, Handle wfmt);
  56. static void                DupRsrc(StringPtr suffix, Handle wfmt, ResType rt, short id);
  57.  
  58. #define keyPascalReply 'PSTR'
  59. #define typePascal     'PSTR'
  60.  
  61.  
  62.  
  63. /*****************************************************************************/
  64.  
  65.  
  66.  
  67. static AEHandler keywordsToInstall[] = {
  68.     { kCustomEventClass, keyWFMTMessage, (AEEventHandlerProcPtr)ReceiveWFMT, nil }
  69. };
  70.  
  71. #define kNumKeywords (sizeof(keywordsToInstall) / sizeof(AEHandler))
  72.  
  73.  
  74.  
  75. /*****************************************************************************/
  76. /*****************************************************************************/
  77.  
  78. #ifdef applec
  79. #pragma segment ATGAppleEvents
  80. #endif
  81.  
  82. /*****************************************************************************/
  83. /*****************************************************************************/
  84.  
  85.  
  86.  
  87. /* Install our custom AppleEvents.  This is done in addition to installing
  88. ** the required AppleEvents.  InitAppleEvents, which installs the required
  89. ** AppleEvents, must be called first, since it sets up some global values. */
  90.  
  91. void    InitWFMTAppleEvents(void)
  92. {
  93.     OSErr    err;
  94.     short    i;
  95.  
  96.     if (gHasAppleEvents) {
  97.  
  98.         for (i = 0; i < kNumKeywords; ++i) {
  99.  
  100.             if (!keywordsToInstall[i].theUPP)
  101.                 keywordsToInstall[i].theUPP = NewAEEventHandlerProc(keywordsToInstall[i].theHandler);
  102.  
  103.             err = AEInstallEventHandler(
  104.                 keywordsToInstall[i].theEventClass,    /* What class to install.  */
  105.                 keywordsToInstall[i].theEventID,    /* Keywords to install.    */
  106.                 keywordsToInstall[i].theUPP,        /* The AppleEvent handler. */
  107.                 0L,                                    /* Unused refcon.           */
  108.                 false                                /* Only for our app.       */
  109.             );
  110.  
  111.             if (err) {
  112.                 HCenteredAlert(rErrorAlert, nil, gAlertFilterUPP);
  113.                 return;
  114.             }
  115.         }
  116.     }
  117. }
  118.  
  119.  
  120.  
  121. /*****************************************************************************/
  122.  
  123.  
  124.  
  125. /* Send a message to the running application for various application-editing functions.
  126. ** This is used by the AppsToGo application editor for editing running applications. */
  127.  
  128. OSErr    SendWFMTMessage(FileRecHndl frHndl, TreeObjHndl wobj, short messageType,
  129.                         ResType rtype, short resID, Handle *resHndl, StringPtr suffix)
  130. {
  131.     AEAddressDesc    remoteLoc;
  132.     OSErr            err;
  133.     AppleEvent        theAevt, reply;
  134.     WindowPtr        oldPort;
  135.     Handle            mssgData;
  136.     long            mssgSize, actualSize, oldSize, blockNum;
  137.     DescType        actualType;
  138.     AEKeyword        keym;
  139.     DescType        typem;
  140.     char            hstate;
  141.  
  142.     if (!(*frHndl)->connect.connected) return(noErr);
  143.  
  144.     oldPort = SetFilePort(frHndl);
  145.  
  146.     theAevt.dataHandle = reply.dataHandle = nil;
  147.         /* Make sure disposing of the descriptors is okay in all cases. */
  148.         /* Even though the AppleEvent manager nils out the handle upon failure,
  149.         ** the below code doesn't necessarily call the AppleEvent manager for each
  150.         ** descriptor.  By etting them to nil here, this allows us to just try to
  151.         ** dispose of the descriptors at the bottom of the function. */
  152.  
  153.     remoteLoc = (*frHndl)->connect.remoteLoc;
  154.  
  155.     err = AECreateAppleEvent(        /* CREATE EMPTY APPLEEVENT.     */
  156.         kCustomEventClass,            /* Event class.                 */
  157.         typeWFMTMessage,            /* Event ID.                 */
  158.         &remoteLoc,                    /* Address of receiving app. */
  159.         kAutoGenerateReturnID,        /* This value causes the     */
  160.                                     /* AppleEvent manager to     */
  161.                                     /* assign a return ID that     */
  162.                                     /* is unique to the session. */
  163.         kAnyTransactionID,            /* Ignore transaction ID.     */
  164.         &theAevt                    /* Location of event.         */
  165.     );
  166.  
  167.     if (!err)            /* Say what the message is. */
  168.         AEPutParamPtr(&theAevt, keyDirectObject, typeShortInteger, (Ptr)&messageType, sizeof(short));
  169.  
  170.     if (!err) {
  171.         blockNum = 0;
  172.         AEPutParamPtr(&theAevt, typeBlockNum, typeBlockNum, (Ptr)&blockNum, sizeof(long));
  173.     }
  174.  
  175.     /* The stuff that applies to all messages is now done.  Now specifically
  176.     ** handle all the different message types. */
  177.  
  178.     mssgData = nil;
  179.  
  180.     if (!err) {
  181.  
  182.         if (messageType == kMergeAppResourcesMssg) messageType = kSetWFMTMssg;
  183.         if (suffix) {
  184.             err = AEPutParamPtr(
  185.                 &theAevt,
  186.                 keyPascalReply,
  187.                 typePascal,
  188.                 (Ptr)suffix,
  189.                 sizeof(Str32)
  190.             );
  191.         }
  192.  
  193.         switch (messageType) {
  194.  
  195.             case kGetWFMTMssg:
  196.                 break;
  197.  
  198.             case kSetWFMTMssg:
  199.                 err = HWriteTree(wobj, mssgData = NewHandle(0));
  200.                 if (!err) {
  201.                     mssgSize = GetHandleSize(mssgData);
  202.                     if (mssgSize > 30000) mssgSize = 30000;
  203.                     HLock(mssgData);
  204.                     err = AEPutParamPtr(
  205.                         &theAevt,
  206.                         keyWFMTMessage,
  207.                         typeWFMTMessage,
  208.                         *mssgData,
  209.                         mssgSize
  210.                     );
  211.                     HUnlock(mssgData);
  212.                 }
  213.                 break;
  214.  
  215.             case kGetAppResourceMssg:
  216.                 err = AEPutParamPtr(
  217.                     &theAevt,
  218.                     typeRSRCType,
  219.                     typeRSRCType,
  220.                     (Ptr)&rtype,
  221.                     sizeof(ResType)
  222.                 );
  223.                 if (!err) {
  224.                     err = AEPutParamPtr(
  225.                         &theAevt,
  226.                         typeRSRCID,
  227.                         typeRSRCID,
  228.                         (Ptr)&resID,
  229.                         sizeof(short)
  230.                     );
  231.                 }
  232.                 break;
  233.  
  234.             case kSetAppResourceMssg:
  235.                 err = AEPutParamPtr(
  236.                     &theAevt,
  237.                     typeRSRCType,
  238.                     typeRSRCType,
  239.                     (Ptr)&rtype,
  240.                     sizeof(ResType)
  241.                 );
  242.                 if (!err) {
  243.                     err = AEPutParamPtr(
  244.                         &theAevt,
  245.                         typeRSRCID,
  246.                         typeRSRCID,
  247.                         (Ptr)&resID,
  248.                         sizeof(short)
  249.                     );
  250.                 }
  251.                 if (!err) {
  252.                     hstate = HGetState(*resHndl);
  253.                     HLock(*resHndl);
  254.                     mssgSize = GetHandleSize(*resHndl);
  255.                     err = AEPutParamPtr(
  256.                         &theAevt,
  257.                         keyWFMTMessage,
  258.                         typeWFMTMessage,
  259.                         **resHndl,
  260.                         mssgSize
  261.                     );
  262.                     HSetState(*resHndl, hstate);
  263.                 }
  264.                 if (!err) {
  265.                     err = AESend(                    /* SEND APPLEEVENT.                */
  266.                         &theAevt,                    /* Our Apple Event to send.        */
  267.                         &reply,                        /* We may have a reply.            */
  268.                         kAEWaitReply,
  269.                         kAENormalPriority,            /* App. send priority.            */
  270.                         300,
  271.                         nil,                        /* No wait, no filter.            */
  272.                         nil                            /* EventFilterProcPtr.            */
  273.                     );
  274.                 }
  275.                 break;
  276.         }
  277.     }
  278.  
  279.     if (!err) {
  280.         if ((messageType == kGetWFMTMssg) || (messageType == kGetAppResourceMssg)) {
  281.  
  282.             if (resHndl) *resHndl = nil;
  283.  
  284.             mssgData = NewHandle(0);
  285.             for (;;) {
  286.  
  287.                 err = AESend(                    /* SEND APPLEEVENT.                */
  288.                     &theAevt,                    /* Our Apple Event to send.        */
  289.                     &reply,                        /* We may have a reply.            */
  290.                     kAEWaitReply,
  291.                     kAENormalPriority,            /* App. send priority.            */
  292.                     300,
  293.                     nil,                        /* No wait, no filter.            */
  294.                     nil                            /* EventFilterProcPtr.            */
  295.                 );
  296.                 if (err) break;
  297.  
  298.                 keym  = (messageType == kGetWFMTMssg) ? keyWFMTMessage  : keyRSRCMessage;
  299.                 typem = (messageType == kGetWFMTMssg) ? typeWFMTMessage : typeRSRCMessage;
  300.                 err = AEGetParamPtr(
  301.                     &reply,                    /* The AppleEvent.              */
  302.                     keym,                    /* AEKeyword                 */
  303.                     typem,                    /* Desired type.             */
  304.                     &actualType,            /* Type code.                 */
  305.                     nil,                    /* Pointer to area for data. */ 
  306.                     0,                        /* Size of data area.         */
  307.                     &mssgSize                /* Returned size of data.     */
  308.                 );
  309.                 if (err) break;
  310.  
  311.                 oldSize = GetHandleSize(mssgData);
  312.                 SetHandleSize(mssgData, oldSize + mssgSize);
  313.                 err = MemError();
  314.                 if (err) break;
  315.  
  316.                 HLock(mssgData);
  317.                 err = AEGetParamPtr(
  318.                     &reply,                    /* The AppleEvent.              */
  319.                     keym,                    /* AEKeyword                 */
  320.                     typem,                    /* Desired type.             */
  321.                     &actualType,            /* Type code.                 */
  322.                     *mssgData + oldSize,    /* Pointer to area for data. */ 
  323.                     mssgSize,                /* Size of data area.         */
  324.                     &actualSize                /* Returned size of data.     */
  325.                 );
  326.                 HUnlock(mssgData);
  327.                 if (err) break;
  328.  
  329.                 if (mssgSize < 30000) break;
  330.  
  331.                 ++blockNum;
  332.                 err = AEPutParamPtr(
  333.                     &theAevt,
  334.                     typeBlockNum,
  335.                     typeBlockNum,
  336.                     (Ptr)&blockNum,
  337.                     sizeof(long)
  338.                 );
  339.                 if (err) break;
  340.  
  341.             }
  342.  
  343.             if (messageType == kGetWFMTMssg) {
  344.                 if (!err)
  345.                     HReadTree(wobj, mssgData);
  346.                 if (mssgData)
  347.                     DisposeHandle(mssgData);
  348.             }
  349.             else {
  350.                 if (err) {
  351.                     if (mssgData) {
  352.                         DisposeHandle(mssgData);
  353.                         mssgData = nil;
  354.                     }
  355.                 }
  356.                 *resHndl = mssgData;
  357.             }
  358.         }
  359.     }
  360.  
  361.     if (!err) {        /* If everything looks good... */
  362.         if (messageType == kSetWFMTMssg) {
  363.             do {
  364.                 if (err) {
  365.                     if (mssgData) {
  366.                         DisposeHandle(mssgData);
  367.                         mssgData = nil;
  368.                     }
  369.                     break;
  370.                 }
  371.                 err = AESend(                    /* SEND APPLEEVENT.                */
  372.                     &theAevt,                    /* Our Apple Event to send.        */
  373.                     &reply,                        /* We may have a reply.            */
  374.                     kAEWaitReply,
  375.                     kAENormalPriority,            /* App. send priority.            */
  376.                     300,
  377.                     nil,                        /* No wait, no filter.            */
  378.                     nil                            /* EventFilterProcPtr.            */
  379.                 );
  380.                 if (err) continue;
  381.                 if (mssgData) {
  382.                     mssgSize = GetHandleSize(mssgData);
  383.                     if (mssgSize < 30000) {
  384.                         DisposeHandle(mssgData);
  385.                         mssgData = nil;
  386.                         break;
  387.                     }
  388.                     mssgSize -= 30000;
  389.                     BlockMove(*mssgData + 30000, *mssgData, mssgSize);
  390.                     SetHandleSize(mssgData, mssgSize);
  391.                     if (mssgSize > 30000) mssgSize = 30000;
  392.                     HLock(mssgData);
  393.                     err = AEPutParamPtr(
  394.                         &theAevt,
  395.                         keyWFMTMessage,
  396.                         typeWFMTMessage,
  397.                         *mssgData,
  398.                         mssgSize
  399.                     );
  400.                     HUnlock(mssgData);
  401.                     if (err) continue;
  402.                     ++blockNum;
  403.                     err = AEPutParamPtr(
  404.                         &theAevt,
  405.                         typeBlockNum,
  406.                         typeBlockNum,
  407.                         (Ptr)&blockNum,
  408.                         sizeof(long)
  409.                     );
  410.                 }
  411.             } while (mssgData);
  412. #if 0
  413.             if (!err) {
  414.                 AEDisposeDesc(&theAevt);
  415.                 AEDisposeDesc(&reply);
  416.                 err = AECreateAppleEvent(        /* CREATE EMPTY APPLEEVENT.     */
  417.                     kCoreEventClass,            /* Event class.                 */
  418.                     kAEOpenApplication,            /* Event ID.                 */
  419.                     &remoteLoc,                    /* Address of receiving app. */
  420.                     kAutoGenerateReturnID,        /* This value causes the     */
  421.                                                 /* AppleEvent manager to     */
  422.                                                 /* assign a return ID that     */
  423.                                                 /* is unique to the session. */
  424.                     kAnyTransactionID,            /* Ignore transaction ID.     */
  425.                     &theAevt                    /* Location of event.         */
  426.                 );
  427.                 if (!err) {
  428.                     err = AESend(                    /* SEND APPLEEVENT.                */
  429.                         &theAevt,                    /* Our Apple Event to send.        */
  430.                         &reply,                        /* We may have a reply.            */
  431.                         kAEWaitReply,
  432.                         kAENormalPriority,            /* App. send priority.            */
  433.                         300,
  434.                         nil,                        /* No wait, no filter.            */
  435.                         nil                            /* EventFilterProcPtr.            */
  436.                     );
  437.                 }
  438.             }
  439. #endif
  440.         }
  441.     }
  442.  
  443.     AEDisposeDesc(&theAevt);
  444.     AEDisposeDesc(&reply);
  445.         /* Dispose of the descriptors, created or not.  If not created, no harm done by calling. */
  446.  
  447.     SetPort(oldPort);
  448.     return(err);
  449. }
  450.  
  451.  
  452.  
  453. /*****************************************************************************/
  454.  
  455.  
  456.  
  457. static pascal OSErr    ReceiveWFMT(AppleEvent *message, AppleEvent *reply, long refcon)
  458. {
  459. #ifndef __MWERKS__
  460. #pragma unused (reply, refcon)
  461. #endif
  462.  
  463.     OSErr            err;
  464.     short            messageType, oldRes, i, vRefNum, resID;
  465.     char            hstate;
  466.     ResType            rtype;
  467.     Handle            oldr, rsrc;
  468.     WindowPtr        window;
  469.     FileRecHndl        frHndl;
  470.     DescType        actualType;
  471.     long            actualSize, dirID, blockNum, blockBeg, blockSiz;
  472.     MenuHandle        menu;
  473.     long            mssgSize, ms;
  474.     Str32            fileName, suffix;
  475.     Handle            mssgData;
  476.     static Handle    accumMssgData;
  477.     static short    count;
  478.  
  479.     err = AEGetParamPtr(        /* GET THE MESSAGE TYPE.     */
  480.         message,                /* The AppleEvent.              */
  481.         keyDirectObject,        /* AEKeyword                 */
  482.         typeShortInteger,        /* Desired type.             */
  483.         &actualType,            /* Type code.                 */
  484.         (Ptr)&messageType,        /* Pointer to area for data. */ 
  485.         sizeof(short),            /* Size of data area.         */
  486.         &actualSize                /* Returned size of data.     */
  487.     );
  488.  
  489.     if (!err) {        /* If everything is cool, then do the specific task... */
  490.  
  491.         pcpy(suffix, "\p copy");
  492.         AEGetParamPtr(
  493.             message,
  494.             keyPascalReply,
  495.             typePascal,
  496.             &actualType,
  497.             (Ptr)suffix,
  498.             sizeof(Str32),
  499.             &actualSize
  500.         );
  501.  
  502.         switch(messageType) {
  503.  
  504.             case kGetWFMTMssg:
  505.                 mssgData = GetAppResource('WFMT', 128, &err);
  506.                 if ((!mssgData) && (!err)) err = resNotFound;
  507.                 if (mssgData) {
  508.                     DetachResource(mssgData);
  509.                     err = AEGetParamPtr(
  510.                         message,
  511.                         typeBlockNum,
  512.                         typeBlockNum,
  513.                         &actualType,
  514.                         (Ptr)&blockNum,
  515.                         sizeof(long),
  516.                         &actualSize
  517.                     );
  518.                     if (!err) {
  519.                         mssgSize = GetHandleSize(mssgData);
  520.                         blockBeg = blockNum * 30000;
  521.                         blockSiz = mssgSize - blockBeg;
  522.                         if (blockSiz < 0)     blockSiz = 0;
  523.                         if (blockSiz > 30000) blockSiz = 30000;
  524.                         HLock(mssgData);
  525.                         err = AEPutParamPtr(
  526.                             reply,
  527.                             keyWFMTMessage,
  528.                             typeWFMTMessage,
  529.                             *mssgData + blockBeg,
  530.                             blockSiz
  531.                         );
  532.                     }
  533.                     DisposeHandle(mssgData);
  534.                     mssgData = nil;
  535.                 }
  536.                 break;
  537.  
  538.             case kSetWFMTMssg:
  539.             case kMergeAppResourcesMssg:
  540.                 err = AEGetParamPtr(
  541.                     message,
  542.                     typeBlockNum,
  543.                     typeBlockNum,
  544.                     &actualType,
  545.                     (Ptr)&blockNum,
  546.                     sizeof(long),
  547.                     &actualSize
  548.                 );
  549.                 if (err) break;
  550.                 err = AEGetParamPtr(
  551.                     message,                /* The AppleEvent.              */
  552.                     keyWFMTMessage,            /* AEKeyword                 */
  553.                     typeWFMTMessage,        /* Desired type.             */
  554.                     &actualType,            /* Type code.                 */
  555.                     nil,                    /* Pointer to area for data. */ 
  556.                     0,                        /* Size of data area.         */
  557.                     &mssgSize                /* Returned size of data.     */
  558.                 );
  559.                 if (err) break;
  560.  
  561.                 if ((blockNum) && (!accumMssgData)) {
  562.                     err = memFullErr;
  563.                     break;
  564.                 }
  565.  
  566.                 if (!blockNum)
  567.                     if (!accumMssgData)
  568.                         accumMssgData = NewHandle(0);
  569.  
  570.                 SetHandleSize(accumMssgData, blockNum * 30000 + mssgSize);
  571.                 err = MemError();
  572.                 if (err) {
  573.                     DisposeHandle(accumMssgData);
  574.                     accumMssgData = nil;
  575.                     break;
  576.                 }
  577.  
  578.                 HLock(accumMssgData);
  579.                 err = AEGetParamPtr(
  580.                     message,                            /* The AppleEvent.              */
  581.                     keyWFMTMessage,                        /* AEKeyword                 */
  582.                     typeWFMTMessage,                    /* Desired type.             */
  583.                     &actualType,                        /* Type code.                 */
  584.                     *accumMssgData + blockNum * 30000,    /* Pointer to area for data. */ 
  585.                     mssgSize,                            /* Size of data area.         */
  586.                     &actualSize                            /* Returned size of data.     */
  587.                 );
  588.                 HUnlock(accumMssgData);
  589.  
  590.                 if (mssgSize == 30000) break;        /* More blocks to come. */
  591.  
  592.                 if (!err) {
  593.                     while ((window = GetNextWindow(nil, 0)) != nil) {
  594.                         frHndl = (FileRecHndl)GetWRefCon(window);
  595.                         (*frHndl)->fileState.docDirty = false;
  596.                             /* Prevent save-before-closing dialogs. */
  597.                         (*frHndl)->fileState.attributes &= (0xFFFFFFFFL - kwHideOnClose);
  598.                             /* Make sure that we aren't just hiding old windows. */
  599.                         DisposeOneWindow(window, kClose);
  600.                         gQuitApplication = false;
  601.                             /* App may only have one window, and when it is closed,
  602.                             ** the app quits.  This behavior of the app is like DA's.
  603.                             ** Prevent the app from quitting. */
  604.                     }
  605.                     if (!err) {
  606.                         oldRes = CurResFile();
  607.                         UseResFile(gAppResRef);
  608.                         SetResLoad(false);
  609.                         oldr = Get1Resource('WFMT', 128);
  610.                         SetResLoad(true);
  611.                         if (oldr) {
  612.                             ms = GetHandleSize(accumMssgData);
  613.                             ReallocateHandle(oldr, ms);
  614.                             err = MemError();
  615.                             if (!err) {
  616.                                 BlockMove(*accumMssgData, *oldr, ms);
  617.                                 ChangedResource(oldr);
  618.                                 WriteResource(oldr);
  619.                                 UpdateResFile(gAppResRef);
  620.                                 DetachResource(oldr);
  621.                                 DisposeHandle(oldr);
  622.                                     /* oldr will still be used briefly as a flag. */
  623.                             }
  624.                             else {
  625.                                 RemoveResource(oldr);
  626.                                 DisposeHandle(oldr);
  627.                                 oldr = nil;
  628.                                     /* oldr will still be used briefly as a flag. */
  629.                             }
  630.                         }
  631.                         if (!oldr) {
  632.                             AddResource(accumMssgData, 'WFMT', 128, nil);
  633.                             ChangedResource(accumMssgData);
  634.                             WriteResource(accumMssgData);
  635.                             UpdateResFile(gAppResRef);
  636.                             DetachResource(accumMssgData);
  637.                         }
  638.                         if (!GetFileLocation(gAppResRef, &vRefNum, &dirID, fileName))
  639.                             FlushVol(nil, vRefNum);
  640.                         UseResFile(oldRes);
  641.                     }
  642.  
  643.                     DupWFMT(suffix, accumMssgData);
  644.                     HReadWindowFormats(accumMssgData);
  645.                 }
  646.  
  647.                 if (accumMssgData) {
  648.                     DisposeHandle(accumMssgData);
  649.                     accumMssgData = nil;
  650.                 }
  651.  
  652.                 if (messageType == kMergeAppResourcesMssg) {
  653.                     oldRes = CurResFile();
  654.                     UseResFile(gAppResRef);
  655.                     for (i = Count1Resources('MENU'); i; --i) {
  656.                         menu = (MenuHandle)Get1IndResource('MENU', i);
  657.                         if (!menu) continue;
  658.                         if (GetMenuHandle(**(short **)menu) == menu) DeleteMenu(**(short **)menu);
  659.                         ReleaseResource((Handle)menu);
  660.                     }
  661.                     UseResFile(oldRes);
  662.                 }
  663.  
  664.                 if (messageType == kMergeAppResourcesMssg) MergeAppResources(suffix);
  665.  
  666.                 if (messageType == kMergeAppResourcesMssg) {
  667.                     UseResFile(gAppResRef);
  668.                     StandardMenuSetup(rMenuBar, mApple);
  669.                     UseResFile(oldRes);
  670.                 }
  671.  
  672.                 OpenRuntimeOnlyAutoNewWindows();
  673.                 DoOpenApplication();
  674.                 DoAEOpenApplication(nil, nil, 0L);
  675.  
  676.                 break;
  677.  
  678.             case kGetAppResourceMssg:
  679.                 err = AEGetParamPtr(
  680.                     message,
  681.                     typeRSRCType,
  682.                     typeRSRCType,
  683.                     &actualType,
  684.                     (Ptr)&rtype,
  685.                     sizeof(ResType),
  686.                     &actualSize
  687.                 );
  688.                 if (!err) {
  689.                     err = AEGetParamPtr(
  690.                         message,
  691.                         typeRSRCID,
  692.                         typeRSRCID,
  693.                         &actualType,
  694.                         (Ptr)&resID,
  695.                         sizeof(long),
  696.                         &actualSize
  697.                     );
  698.                 }
  699.                 if (!err) {
  700.                     rsrc = GetAppResource(rtype, resID, nil);
  701.                     if (rsrc) {
  702.                         hstate = HGetState(rsrc);
  703.                         HLock(rsrc);
  704.                         err = AEGetParamPtr(
  705.                             message,
  706.                             typeBlockNum,
  707.                             typeBlockNum,
  708.                             &actualType,
  709.                             (Ptr)&blockNum,
  710.                             sizeof(long),
  711.                             &actualSize
  712.                         );
  713.                         if (!err) {
  714.                             mssgSize = GetHandleSize(rsrc);
  715.                             blockBeg = blockNum * 30000;
  716.                             blockSiz = mssgSize - blockBeg;
  717.                             if (blockSiz < 0)     blockSiz = 0;
  718.                             if (blockSiz > 30000) blockSiz = 30000;
  719.                             err = AEPutParamPtr(
  720.                                 reply,
  721.                                 keyRSRCMessage,
  722.                                 typeRSRCMessage,
  723.                                 *rsrc + blockBeg,
  724.                                 mssgSize
  725.                             );
  726.                         }
  727.                         HSetState(rsrc, hstate);
  728.                     }
  729.                 }
  730.                 break;
  731.  
  732.             case kSetAppResourceMssg:
  733.                 err = AEGetParamPtr(
  734.                     message,
  735.                     typeRSRCType,
  736.                     typeRSRCType,
  737.                     &actualType,
  738.                     (Ptr)&rtype,
  739.                     sizeof(ResType),
  740.                     &actualSize
  741.                 );
  742.                 if (!err) {
  743.                     err = AEGetParamPtr(
  744.                         message,
  745.                         typeRSRCID,
  746.                         typeRSRCID,
  747.                         &actualType,
  748.                         (Ptr)&resID,
  749.                         sizeof(long),
  750.                         &actualSize
  751.                     );
  752.                 }
  753.                 err = AEGetParamPtr(
  754.                     message,                /* The AppleEvent.              */
  755.                     keyWFMTMessage,            /* AEKeyword                 */
  756.                     typeWFMTMessage,        /* Desired type.             */
  757.                     &actualType,            /* Type code.                 */
  758.                     nil,                    /* Pointer to area for data. */ 
  759.                     0,                        /* Size of data area.         */
  760.                     &mssgSize                /* Returned size of data.     */
  761.                 );
  762.                 if (err) break;
  763.                 mssgData = NewHandle(mssgSize);
  764.                 if (!mssgData) break;
  765.                 HLock(mssgData);
  766.                 err = AEGetParamPtr(
  767.                     message,                /* The AppleEvent.              */
  768.                     keyWFMTMessage,            /* AEKeyword                 */
  769.                     typeWFMTMessage,        /* Desired type.             */
  770.                     &actualType,            /* Type code.                 */
  771.                     *mssgData,                /* Pointer to area for data. */ 
  772.                     mssgSize,                /* Size of data area.         */
  773.                     &actualSize                /* Returned size of data.     */
  774.                 );
  775.                 HUnlock(mssgData);
  776.                 if (!err) {
  777.                     oldRes = CurResFile();
  778.                     UseResFile(gAppResRef);
  779.                     oldr = Get1Resource(rtype, resID);
  780.                     if (oldr) {
  781.                         RemoveResource(oldr);
  782.                         DisposeHandle(oldr);
  783.                     }
  784.                     AddResource(mssgData, rtype, resID, nil);
  785.                     ChangedResource(mssgData);
  786.                     WriteResource(mssgData);
  787.                     UpdateResFile(gAppResRef);
  788.                     DetachResource(mssgData);
  789.                     if (!GetFileLocation(gAppResRef, &vRefNum, &dirID, fileName))
  790.                         FlushVol(nil, vRefNum);
  791.                     UseResFile(oldRes);
  792.                     DupRsrc(suffix, mssgData, rtype, resID);
  793.                 }
  794.                 DisposeHandle(mssgData);
  795.                 break;
  796.         }
  797.     }
  798.  
  799.     return(err);
  800. }
  801.  
  802.  
  803.  
  804.  
  805. /*****************************************************************************/
  806. /*****************************************************************************/
  807. /*****************************************************************************/
  808.  
  809.  
  810.  
  811. static void    MergeAppResources(StringPtr suffix)
  812. {
  813.     short                oldRes, numAppTypes, numAppItems, numCpyTypes, numCpyItems;
  814.     short                tt, ii, dd, mergeRsrc, rid, cid, vRefNum;
  815.     char                appAttr, cpyAttr;
  816.     ResType                appType, cpyType, rtype, ddType, ctype;
  817.     long                l, cpySize, dirID;
  818.     ProcessSerialNumber    psn;
  819.     ProcessInfoRec        pinfo;
  820.     FSSpec                fss;
  821.     Str255                rname, cname;
  822.     Str32                dontDo, fileName;
  823.     Handle                appr, cpyr;
  824.     OSErr                err;
  825.  
  826.     oldRes = CurResFile();
  827.  
  828.     pinfo.processInfoLength = sizeof(ProcessInfoRec);
  829.     pinfo.processName       = gAppName;
  830.     pinfo.processAppSpec    = &fss;
  831.  
  832.     psn.lowLongOfPSN  = kCurrentProcess;
  833.     psn.highLongOfPSN = kNoProcess;
  834.     GetProcessInformation(&psn, &pinfo);
  835.  
  836.     pcat(fss.name, suffix);
  837.  
  838.     SetResLoad(false);
  839.     mergeRsrc = HOpenResFile(fss.vRefNum, fss.parID, fss.name, fsRdPerm);
  840.     err = ResError();
  841.     SetResLoad(true);
  842.     if (err) return;
  843.  
  844.     UseResFile(gAppResRef);
  845.     numAppTypes = Count1Types();
  846.  
  847.     for (tt = numAppTypes; tt; --tt) {
  848.         Get1IndType(&appType, tt);
  849.         numAppItems = Count1Resources(appType);
  850.  
  851.         for (ii = numAppItems; ii; --ii) {
  852.  
  853.             appr = Get1IndResource(appType, ii);
  854.             if (!appr) continue;
  855.  
  856.             GetResInfo(appr, &rid, &rtype, rname);
  857.             appAttr  = GetResAttrs(appr);
  858.  
  859.             if (rtype == 'WFMT') continue;
  860.                 /* ResEdit doesn't modify this one.  DTSFW.App.Editor does. */
  861.  
  862.             if ((rtype == 'STR#') && (rid == 128)) continue;
  863.                 /* This is the resource that describes what resources can be replaced/modified.
  864.                 ** We don't want to replace or modify what is telling us what to do. */
  865.  
  866.             for (dd = 1;; ++dd) {
  867.                 GetIndString(dontDo, 128, dd);
  868.                 if (!dontDo[0]) break;
  869.                 BlockMove(dontDo + 1, &ddType, sizeof(long));
  870.                 if (appType == ddType) break;
  871.             }
  872.             if (dontDo[0]) continue;
  873.  
  874.             UseResFile(mergeRsrc);
  875.             cpyr = Get1Resource(rtype, rid);
  876.             if (cpyr) {
  877.                 GetResInfo(cpyr, &cid, &ctype, cname);
  878.                 cpyAttr = GetResAttrs(cpyr);
  879.                 DetachResource(cpyr);
  880.                 HNoPurge(cpyr);
  881.             }
  882.             UseResFile(gAppResRef);
  883.             appr = Get1IndResource(appType, ii);        /* In case it's purgeable and got purged. */
  884.             if (!appr) {                                /* Just to be really safe. */
  885.                 DisposeHandle(cpyr);
  886.                 continue;
  887.             }
  888.  
  889.             if (!cpyr) {
  890.                 RemoveResource(appr);
  891.                 DisposeHandle(appr);
  892.                 continue;
  893.             }
  894.  
  895.             if (appAttr != cpyAttr) {
  896.                 SetResAttrs(appr, cpyAttr);
  897.                 ChangedResource(appr);
  898.                 WriteResource(appr);
  899.             }
  900.             appr = Get1IndResource(appType, ii);        /* In case it's purgeable and got purged. */
  901.             if (!appr) {                                /* Just to be really safe. */
  902.                 DisposeHandle(cpyr);
  903.                 continue;
  904.             }
  905.  
  906.             if (pcmp(rname, cname)) {
  907.                 SetResInfo(appr, rid, cname);
  908.                 ChangedResource(appr);
  909.                 WriteResource(appr);
  910.             }
  911.             appr = Get1IndResource(appType, ii);        /* In case it's purgeable and got purged. */
  912.             if (!appr) {                                /* Just to be really safe. */
  913.                 DisposeHandle(cpyr);
  914.                 continue;
  915.             }
  916.  
  917.             if (GetHandleSize(appr) != (cpySize = GetHandleSize(cpyr))) {
  918.                 HNoPurge(appr);
  919.                 HUnlock(appr);
  920.                 SetHandleSize(appr, cpySize);
  921.                 err = MemError();
  922.                 SetResAttrs(appr, cpyAttr);
  923.                 if (err) {
  924.                     DisposeHandle(cpyr);
  925.                     continue;
  926.                 }
  927.                 BlockMove(*cpyr, *appr, cpySize);
  928.                 ChangedResource(appr);
  929.                 WriteResource(appr);
  930.                 DisposeHandle(cpyr);
  931.                 continue;
  932.             }
  933.  
  934.             for (l = 0; l < cpySize; ++l) {
  935.                 if ((*appr)[l] != (*cpyr)[l]) {
  936.                     BlockMove(*cpyr, *appr, cpySize);
  937.                     ChangedResource(appr);
  938.                     WriteResource(appr);
  939.                     DisposeHandle(cpyr);
  940.                     break;
  941.                 }
  942.             }
  943.             if (l < cpySize) continue;
  944.  
  945.             DisposeHandle(cpyr);
  946.         }
  947.     }
  948.  
  949.     UseResFile(mergeRsrc);
  950.     numCpyTypes = Count1Types();
  951.  
  952.     for (tt = numCpyTypes; tt; --tt) {
  953.         Get1IndType(&cpyType, tt);
  954.         numCpyItems = Count1Resources(cpyType);
  955.  
  956.         for (ii = numCpyItems; ii; --ii) {
  957.  
  958.             cpyr = Get1IndResource(cpyType, ii);
  959.             if (!cpyr) continue;
  960.  
  961.             cpyAttr = GetResAttrs(cpyr);
  962.             GetResInfo(cpyr, &cid, &ctype, cname);
  963.             DetachResource(cpyr);
  964.  
  965.             UseResFile(gAppResRef);
  966.             appr = Get1Resource(ctype, cid);
  967.             UseResFile(mergeRsrc);
  968.  
  969.             if (!appr) {
  970.                 UseResFile(gAppResRef);
  971.                 AddResource(cpyr, ctype, cid, cname);
  972.                 SetResAttrs(cpyr, cpyAttr);
  973.                 ChangedResource(cpyr);
  974.                 WriteResource(cpyr);
  975.                 DetachResource(cpyr);
  976.                 UseResFile(mergeRsrc);
  977.             }
  978.  
  979.             DisposeHandle(cpyr);
  980.         }
  981.     }
  982.  
  983.     CloseResFile(mergeRsrc);
  984.     UpdateResFile(gAppResRef);
  985.  
  986.     if (!GetFileLocation(gAppResRef, &vRefNum, &dirID, fileName))
  987.         FlushVol(nil, vRefNum);
  988.  
  989.     UseResFile(oldRes);
  990. }
  991.  
  992.  
  993.  
  994. static void    DupWFMT(StringPtr suffix, Handle wfmt)
  995. {
  996.     short                oldRes;
  997.     short                mergeRsrc;
  998.     long                ms;
  999.     ProcessSerialNumber    psn;
  1000.     ProcessInfoRec        pinfo;
  1001.     FSSpec                fss;
  1002.     Handle                oldr;
  1003.     OSErr                err;
  1004.  
  1005.     oldRes = CurResFile();
  1006.  
  1007.     pinfo.processInfoLength = sizeof(ProcessInfoRec);
  1008.     pinfo.processName       = gAppName;
  1009.     pinfo.processAppSpec    = &fss;
  1010.  
  1011.     psn.lowLongOfPSN  = kCurrentProcess;
  1012.     psn.highLongOfPSN = kNoProcess;
  1013.     GetProcessInformation(&psn, &pinfo);
  1014.  
  1015.     pcat(fss.name, suffix);
  1016.  
  1017.     SetResLoad(false);
  1018.     mergeRsrc = HOpenResFile(fss.vRefNum, fss.parID, fss.name, fsRdWrPerm);
  1019.     err = ResError();
  1020.     SetResLoad(true);
  1021.     if (err) return;
  1022.  
  1023.     UseResFile(mergeRsrc);
  1024.     SetResLoad(false);
  1025.     oldr = Get1Resource('WFMT', 128);
  1026.     SetResLoad(true);
  1027.     if (oldr) {
  1028.         ms = GetHandleSize(wfmt);
  1029.         ReallocateHandle(oldr, ms);
  1030.         err = MemError();
  1031.         if (!err) {
  1032.             BlockMove(*wfmt, *oldr, ms);
  1033.             ChangedResource(oldr);
  1034.             WriteResource(oldr);
  1035.             UpdateResFile(mergeRsrc);
  1036.             DetachResource(oldr);
  1037.             DisposeHandle(oldr);
  1038.                 /* oldr will still be used briefly as a flag. */
  1039.         }
  1040.         else {
  1041.             RemoveResource(oldr);
  1042.             DisposeHandle(oldr);
  1043.             oldr = nil;
  1044.                 /* oldr will still be used briefly as a flag. */
  1045.         }
  1046.     }
  1047.     if (!oldr) {
  1048.         AddResource(wfmt, 'WFMT', 128, nil);
  1049.         ChangedResource(wfmt);
  1050.         WriteResource(wfmt);
  1051.         DetachResource(wfmt);
  1052.     }
  1053.  
  1054.     CloseResFile(mergeRsrc);
  1055.     UseResFile(oldRes);
  1056. }
  1057.  
  1058.  
  1059.  
  1060. static void    DupRsrc(StringPtr suffix, Handle data, ResType rt, short id)
  1061. {
  1062.     short                oldRes;
  1063.     short                mergeRsrc;
  1064.     long                ms;
  1065.     ProcessSerialNumber    psn;
  1066.     ProcessInfoRec        pinfo;
  1067.     FSSpec                fss;
  1068.     Handle                oldr;
  1069.     OSErr                err;
  1070.  
  1071.     oldRes = CurResFile();
  1072.  
  1073.     pinfo.processInfoLength = sizeof(ProcessInfoRec);
  1074.     pinfo.processName       = gAppName;
  1075.     pinfo.processAppSpec    = &fss;
  1076.  
  1077.     psn.lowLongOfPSN  = kCurrentProcess;
  1078.     psn.highLongOfPSN = kNoProcess;
  1079.     GetProcessInformation(&psn, &pinfo);
  1080.  
  1081.     pcat(fss.name, suffix);
  1082.  
  1083.     SetResLoad(false);
  1084.     mergeRsrc = HOpenResFile(fss.vRefNum, fss.parID, fss.name, fsRdWrPerm);
  1085.     err = ResError();
  1086.     SetResLoad(true);
  1087.     if (err) return;
  1088.  
  1089.     UseResFile(mergeRsrc);
  1090.     SetResLoad(false);
  1091.     oldr = Get1Resource(rt, id);
  1092.     SetResLoad(true);
  1093.     if (oldr) {
  1094.         ms = GetHandleSize(data);
  1095.         ReallocateHandle(oldr, ms);
  1096.         err = MemError();
  1097.         if (!err) {
  1098.             BlockMove(*data, *oldr, ms);
  1099.             ChangedResource(oldr);
  1100.             WriteResource(oldr);
  1101.             UpdateResFile(mergeRsrc);
  1102.             DetachResource(oldr);
  1103.             DisposeHandle(oldr);
  1104.                 /* oldr will still be used briefly as a flag. */
  1105.         }
  1106.     }
  1107.  
  1108.     CloseResFile(mergeRsrc);
  1109.     UseResFile(oldRes);
  1110. }
  1111.  
  1112.  
  1113.  
  1114.